<?php

/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/9/29
 * Time: 17:19
 */

/**
 * Class HttpRequest
 * @User: yfl
 * @Time: 2017年9月29日 17:20:26
 * @description:PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
 * @from http://www.jb51.net/article/55551.htm
 * HttpRequest class, HTTP请求类，支持GET,POST,Multipart/form-data
 * Ver:  1.0
 * Func:  *  public setConfig
 * 设置连接参数
 *  public setFormdata  设置表单数据
 *  public setFiledata  设置文件数据
 *  public send     发送数据
 *  private connect    创建连接
 *  private disconnect  断开连接
 *  private sendGet    get 方式,处理发送的数据,不会处理文件数据
 *  private sendPost   post 方式,处理发送的数据
 *  private sendMultipart multipart 方式,处理发送的数据,发送文件推荐使用此方式  */

require_once '../common_funtion.php';

class HttpRequest
{
    private $_ip = '';
    private $_host = '';
    private $_url = '';
    private $_port = '';
    private $_errno = '';
    private $_errstr = '';
    private $_timeout = 15;
    private $_fp = null;
    private $_formdata = array();
    private $_filedata = array();

    // 设置连接参数
    public function setConfig(array $config)
    {
        $this->_ip = isset($config['ip']) ? $config['ip'] : '';
        $this->_host = isset($config['host']) ? $config['host'] : '';
        $this->_url = isset($config['url']) ? $config['url'] : '';
        $this->_port = isset($config['port']) ? $config['port'] : 80;
        $this->_errno = isset($config['errno']) ? $config['errno'] : '';
        $this->_errstr = isset($config['errstr']) ? $config['errstr'] : '';
        $this->_timeout = isset($confg['timeout']) ? $config['timeout'] : 15;
        // 如没有设置ip，则用host代替
        if ($this->_ip == '') {
            $this->_ip = $this->_host;
        }
    }

    //设置表单数据
    public function setFormData(array $formData = array())
    {
        $this->_formdata = $formData;
    }

    //设置文件数据
    public function setFileData(array $fileData = array())
    {
        $this->_filedata = $fileData;

    }

    // 发送发送数据
    public function send($type = 'get')
    {
        $type = strtolower($type);
        if ($this->connect()) {
            switch ($type) {
                case 'get':
                    $out = $this->sendGet();
                    break;
                case 'post':
                    $out = $this->sendPost();
                    break;
                case 'multipart':
                    $out = $this->sendMultipart();
            }
            if ($out === false) {
                return false;
            }
            //发送数据
            fwrite($this->_fp, $out);//fputs() 函数是 fwrite() 函数的别名。
            //读取返回的数据
            $response = '';
            while (!feof($this->_fp)) {
                $row = fread($this->_fp, 128);
                $response .= $row;
            };
            //断开连接 释放资源
            $this->disConnect();

            $pos = strpos($response, "\r\n\r\n");

            $response = substr($response, $pos + 4);

            return $response;
        } else {
            return false;
        }
    }

    /**
     * @return bool
     * @User: yfl
     * @Time: 2017年9月30日 11:01:52
     * @description:创建连接
     */
    private function connect()
    {
        $this->_fp = fsockopen($this->_ip, $this->_port, $this->_errno, $this->_errstr, $this->_timeout);
        if ($this->_fp === false) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * @User: yfl
     * @Time: 2017年9月30日 10:41:44
     * @description:断开连接
     */
    private function disConnect()
    {
        if ($this->_fp != null) {
            fclose($this->_fp);
            $this->_fp = null;
        }
    }

    /**
     * @return bool|string
     * @User: yfl
     * @Time: 2017年9月29日 13:29:43
     * @description:get 方式,处理发送的数据,不会处理文件数据
     */
    private function sendGet()
    {
        // 检查是否空数据
        if (!$this->_formdata) {
            return false;
        }
        // 处理url
        $url = $this->_url . '?' . http_build_query($this->_formdata);
        $out = "GET " . $url . " http/1.1\r\n";
        $out .= "host: " . $this->_host . "\r\n";
        $out .= "Connection: close\r\n\r\n";
        return $out;
    }

    /**
     * @return bool|string
     * @User: yfl
     * @Time: 2017年9月29日 14:29:18
     * @description:post 方式,处理发送的数据
     */
    private function sendPost()
    {
        // 检查是否空数据
        if (empty($this->_formdata) && empty($this->_filedata)) {
            return false;
        }
        // form data
        $data = $this->_formdata ? $this->_formdata : array();
        // file data
        if ($this->_filedata) {
            foreach ($this->_filedata as $filedata) {
                if (file_exists($filedata['path'])) {
                    $data[$filedata['name']] = file_get_contents($filedata['path']);
                }
            }
        }
        if (empty($data)) {
            return false;
        }
        $data = http_build_query($data);
        $out = "POST " . $this->_url . " http/1.1\r\n";
        $out .= "host: " . $this->_host . "\r\n";
        $out .= "content-type: application/x-www-form-urlencoded\r\n";
        $out .= "content-length: " . strlen($data) . "\r\n";
        $out .= "connection: close\r\n\r\n";
        $out .= $data;
        return $out;

    }

    /**
     * @return bool|string
     * @User: yfl
     * @Time: 2017年9月30日 10:29:00
     * @description:multipart 方式,处理发送的数据,发送文件推荐使用此方式
     */
    private function sendMultipart()
    {
        // 检查是否空数据
        if (empty($this->_formdata) && empty($this->_filedata)) {
            return false;
        }
        // 设置分割标识
//        srand((double)microtime() * 1000000);
        $boundary = '---------------------------' . substr(md5(rand(0, 32000)), 0, 10);
        $data = '--' . $boundary . "\r\n";
        // form data
        $formdata = '';
        foreach ($this->_formdata as $key => $val) {
            $formdata .= "content-disposition: form-data; name=\"" . $key . "\"\r\n";
            $formdata .= "content-type: text/plain\r\n\r\n";
            if (is_array($val)) {
                $formdata .= json_encode($val) . "\r\n"; // 数组使用json encode后方便处理
            } else {
                $formdata .= rawurlencode($val) . "\r\n";
            }
            $formdata .= '--' . $boundary . "\r\n";
        }
        // file data
        $filedata = '';

        foreach ($this->_filedata as $val) {
            if (file_exists($val['path'])) {
                $filedata .= "content-disposition: form-data; name=\"" . $val['name'] . "\"; filename=\"" . $val['filename'] . "\"\r\n";
                $filedata .= "content-type: " . $this->_mime_content_type($val['path']) . "\r\n\r\n";
                $filedata .= implode('', file($val['path'])) . "\r\n";
                $filedata .= '--' . $boundary . "\r\n";
            }
        }
        if (empty($formdata) && empty($filedata)) {
            return false;
        }
        $data .= $formdata . $filedata . "--\r\n\r\n";

        $out = "POST " . $this->_url . " http/1.1\r\n";
        $out .= "host: " . $this->_host . "\r\n";
        $out .= "content-type: multipart/form-data; boundary=" . $boundary . "\r\n";
        $out .= "content-length: " . strlen($data) . "\r\n";
        $out .= "connection: close\r\n\r\n";
        $out .= $data;

        return $out;
    }

    private function _mime_content_type($filename)
    {

        $mime_types = array(

            'txt' => 'text/plain',
            'htm' => 'text/html',
            'html' => 'text/html',
            'php' => 'text/html',
            'css' => 'text/css',
            'js' => 'application/javascript',
            'json' => 'application/json',
            'xml' => 'application/xml',
            'swf' => 'application/x-shockwave-flash',
            'flv' => 'video/x-flv',

            // images
            'png' => 'image/png',
            'jpe' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'jpg' => 'image/jpeg',
            'gif' => 'image/gif',
            'bmp' => 'image/bmp',
            'ico' => 'image/vnd.microsoft.icon',
            'tiff' => 'image/tiff',
            'tif' => 'image/tiff',
            'svg' => 'image/svg+xml',
            'svgz' => 'image/svg+xml',

            // archives
            'zip' => 'application/zip',
            'rar' => 'application/x-rar-compressed',
            'exe' => 'application/x-msdownload',
            'msi' => 'application/x-msdownload',
            'cab' => 'application/vnd.ms-cab-compressed',

            // audio/video
            'mp3' => 'audio/mpeg',
            'qt' => 'video/quicktime',
            'mov' => 'video/quicktime',

            // adobe
            'pdf' => 'application/pdf',
            'psd' => 'image/vnd.adobe.photoshop',
            'ai' => 'application/postscript',
            'eps' => 'application/postscript',
            'ps' => 'application/postscript',

            // ms office
            'doc' => 'application/msword',
            'rtf' => 'application/rtf',
            'xls' => 'application/vnd.ms-excel',
            'ppt' => 'application/vnd.ms-powerpoint',

            // open office
            'odt' => 'application/vnd.oasis.opendocument.text',
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
        );
        $arr = explode('.', $filename);
        $ext = strtolower(array_pop($arr));
        if (array_key_exists($ext, $mime_types)) {
            return $mime_types[$ext];
        } elseif (function_exists('finfo_open')) {
            $finfo = finfo_open(FILEINFO_MIME);
            $mimetype = finfo_file($finfo, $filename);
            finfo_close($finfo);
            return $mimetype;
        } else {
            return 'application/octet-stream';
        }

    }
}